#ifndef UTILS_H
#define UTILS_H

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <QString>
#include <vector>
#include "student.h"
#include "book.h"
#include <time.h>

#include <iomanip>
#include <string>
#include <sstream>

using namespace bookandrecord;
using namespace student;
namespace utils {
FILE* openfile(const char* filename, int size);
QString str2Qstr(string str);
string Qstr2str(QString str);
int judge_user(string str);
int judge_menu(string str);
string UtfToGbk(const char* strValue);
QString fomatTime(time_t timep);
int isDigitStr(QString src);
int judgeSpace(string str);
void addLog(string log);

//hash
string sha1(string);
string rand_str(const int len);

//!!!大坑，template模板函数必须写在.h里，写在.cpp里会报错

//ID快速查找法：按照ID搜索参数为（ID，文件路径），使用时需要指定<数据类型>
template<typename T>
T* search(int ID, const char* path) {        // 根据ID查询信息
    auto size = sizeof (T);                  //学生类的大小
    FILE *file = openfile(path, size);       //打开文件
    T* temp = new T;                         //新建一个临时储存类型
    fseek(file, 0, SEEK_END);//fseek将文件指针指到文件末尾
    auto offset = ftell(file);//ftell得到文件从指针到文件头的大小（offset是文件总大小）
    memset(temp, 0, sizeof (T));             //所有信息先赋值为0
    if(ID >= (int)(offset / size))
        return temp;
    else {
        fseek(file, size * ID, SEEK_SET);        //将指针移到该放的地方
        fread(temp, size, 1, file);              //读出需要查询的同学数据
        fclose(file);                            //关闭文件
        return temp;
    }
}


//准确搜索(只返回一个值)，遍历查找法：按照某一项遍历查找，参数为（string 目的成员，string 搜索的字段，文件路径），使用时需要指定<数据类型>
template<typename T>
T * search_oneReturn(string member, string field, const char* path) {
    auto size = sizeof (T);//类的大小
    FILE *file = openfile(path, size); //打开文件
    fseek(file, 0, SEEK_END);//fseek将文件指针指到文件末尾
    auto offset = ftell(file);//ftell得到文件从指针到文件头的大小（offset是文件总大小）
    int count = offset / size; //确定文件总学生信息
    T* temp = new T;                         //新建一个临时储存类型
    memset(temp, 0, sizeof (T));             //所有信息先赋值为0
    T* stu = new T;                         //新建一个临时储存类型
    memset(stu, 0, sizeof (T));

    fseek(file, 0, SEEK_SET);   //将指针指到文件头

    char* matchField;


    for(int i = 0; i < count; i++) { //遍历数据
        fread(stu, size, 1, file); //依次读出并对比学号
        if(member == "stu_id")
            matchField = stu->stu_id;
        if(member == "name")
            matchField = stu->name;
        if(strcmp(matchField, field.c_str()) == 0) {
            return stu;         //得到学号就该学生
        } else ;
    }
    fclose(file);                           //关闭文件
    return temp;    //若未找到，则返回全0的结构体
}


//多返回搜索，可调节是否使用模糊搜索,参数为（string 是否使用模糊搜索，string 表中的要搜索的字段，string 搜索关键词，文件路径）
template<typename T>
vector<T*> search_multipleReturn(string fuzzySearchCondition, string field, string searchKey, const char* path) {
    auto size = sizeof (T);                 //学生类的大小
    FILE *file = openfile(path, size);      //打开文件
    fseek(file, 0, SEEK_END);               //fseek将文件指针指到文件末尾
    auto offset = ftell(file);              //ftell得到文件从指针到文件头的大小（offset是文件总大小）
    int count = offset / size;              //确定文件总学生信息
    T* temp = new T;                        //新建一个临时储存类型
    memset(temp, 0, sizeof (T));            //所有信息先赋值为0
    fseek(file, 0, SEEK_SET);               //将指针指到文件头

    vector<T*> matchList;
    matchList.clear();

    char* matchField = NULL;
    if(field == "stu_id")
        matchField = temp->stu_id;
    if(field == "name")
        matchField = temp->name;

    //不使用模糊搜索
    if(fuzzySearchCondition == "notFuzzySearch") {
        for(int i = 0; i < count; i++) {                             //遍历数据
            fread(temp, size, 1, file);                              //依次读出并对比学号

            if(strcmp(matchField, searchKey.c_str()) == 0) {         //！！！大坑，不能直接存temp，temp是指针位置最后会跳到文件尾
                T* temp2 = new T;                                    //每次新建一个空间储存新找到的数据结构体
                memset(temp2, 0, sizeof (T));                        //新建的结构体所有信息先赋值为0
                memcpy(temp2, temp, sizeof(T));                      //把temp内存整体复制到temp2
                matchList.push_back(temp2);
            }

        }
    }
    //使用模糊搜索
    else if(fuzzySearchCondition == "useFuzzySearch") {
        for(int i = 0; i < count; i++) {                            //遍历数据
            fread(temp, size, 1, file);                             //依次读出并对比学号

            string tempStr = matchField;
            if(tempStr.find(searchKey.c_str()) != tempStr.npos) {   //！！！大坑，不能直接存temp，temp是指针位置最后会跳到文件尾
                T* temp2 = new T;                                   //每次新建一个空间储存新找到的数据结构体
                memset(temp2, 0, sizeof (T));                       //新建的结构体所有信息先赋值为0
                memcpy(temp2, temp, sizeof(T));                     //把temp内存整体复制到temp2
                matchList.push_back(temp2);
            }

        }
    }
    fclose(file);
    return matchList;
}


//改写文件数据，ID查找，参数为（string member, 改写数据， int ID， 文件路径）
//                           改写的数据类型  改写的大小   通过ID查找
template<typename T1, typename T2>
bool reWrite(string member, T1 data, int ID, const char* path) {
    auto size = sizeof(T2);
    T2* temp = new T2;                        //新建一个临时储存类型
    memset(temp, 0, size);           //所有信息先赋值为0
    FILE *file = openfile(path, size);       //打开文件
    fseek(file, size * ID, SEEK_SET);        //将指针移到该放的地方
    fread(temp, size, 1, file);              //读出需要查询的数据
//    if(member == "condition")
//        temp->condition = data;
//    if(member == "all_Borrow")
//        temp->all_Borrow = data;
//    if(member == "borrow_num")
//        temp->borrow_num = data;
//    if(member == "count" )
//        temp->count = data;
//    if(member == "exist")
//        temp->exist = data;
    //多多益善

    fseek(file, size * ID, SEEK_SET);//将指针指回
    fwrite(temp, size, 1, file);//将已经修改的内容写回文件
    delete temp;//释放中间变量
    fclose(file);                            //关闭文件
}

//改写文件数据，直接用新结构体覆盖到原来位置
template<typename T>
void rewrite(int ID, T* mystruct, const char* dataPath) {
    auto size = sizeof(T);
    FILE *file = openfile(dataPath, size);       //打开文件
    fseek(file, size * ID, SEEK_SET);        //将指针移到该放的地方
    fwrite(mystruct, size, 1, file);//将已经修改的内容写回文件
    fclose(file);                            //关闭文件
}


//删除（将exist置0）
template<typename T>
void deleteItem(int ID, const char* dataPath) {
    T* temp = new T;
    auto size = sizeof(T);
    FILE *file = openfile(dataPath, size);       //打开文件
    fseek(file, size * ID, SEEK_SET);        //将指针移到该放的地方
    fread(temp, size, 1, file);              //将对应位置数据读取到temp中
    temp->exist = 0;                         //将exist置0
    fseek(file, size * ID, SEEK_SET);        //将指针移到该放的地方
    fwrite(temp, size, 1, file);             //将temp写入
    fclose(file);
}

}

#endif // UTILS_H
